home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
System Booster
/
System Booster.iso
/
Archives
/
ForCLI
/
DiffDir.lha
/
DiffDir
/
MRDates.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-11-20
|
15KB
|
511 lines
/*
MRDates - AmigaDOS date support routines.
07/03/88
This package is a hybrid of code from Thad Floryan, Doug Merrit and
myself. I wanted a reliable set of AmigaDOS date conversion routines
and this combination seems to work pretty well. The star of the show
here is Thad's algorithm for converting the "days elapsed" field of
an AmigaDOS DateStamp, using an intermediate Julian date format. I
lifted/embellished some of the data structures from Doug's ShowDate
package and wrote the DateToDS function.
History: (most recent change first)
12/31/88 -MRR-
StrToDS was not handling the null string properly.
11/01/88 -MRR- Added Unix-style documentation.
07/03/88 - Changed some names:
Str2DS => StrToDS
DS2Str => DSToStr
*/
#define MRDATES
#include "MRDates.h"
#include <exec/types.h>
#include <ctype.h>
char *index();
#define DATE_SEPARATORS "/:-."
#define MINS_PER_HOUR 60
#define SECS_PER_MIN 60
#define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR)
#define TICS_PER_SEC 50
#define YEARS_PER_CENTURY 100
/*
definitions to calculate current date
*/
#define FEB 1 /* index of feb. in table (for leap years) */
#define DAYS_PER_WEEK 7
#define DAYS_PER_YEAR 365
#define YEARS_PER_LEAP 4
#define START_YEAR 1978
#define FIRST_LEAP_YEAR 1980
#define LEAP_ADJUST (FIRST_LEAP_YEAR - START_YEAR)
#define LEAP_FEB_DAYS 29
#define NORM_FEB_DAYS 28
#define IsLeap(N) (((N) % YEARS_PER_LEAP) ? 0 : 1)
/* FUNCTION
DSToDate - convert a DateStamp to a DATE.
SYNOPSIS
int DSToDate(dateStamp, date)
struct DateStamp *dateStamp;
DATE *date;
DESCRIPTION
Extracts the date components from an AmigaDOS datestamp.
The calculations herein use the following assertions:
146097 = number of days in 400 years per 400 * 365.2425 = 146097.00
36524 = number of days in 100 years per 100 * 365.2425 = 36524.25
1461 = number of days in 4 years per 4 * 365.2425 = 1460.97
AUTHOR
Thad Floryan, 12-NOV-85
Mods by Mark Rinfret, 04-JUL-88
SEE ALSO
Include file MRDates.h.
*/
#define DDELTA 722449 /* days from Jan.1,0000 to Jan.1,1978 */
static int mthvec[] =
{-1, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364};
int
DSToDate(ds, date)
long *ds; DATE *date;
{
long jdate, day0, day1, day2, day3;
long year, month, day, temp;
jdate = ds[0] + DDELTA; /* adjust internal date to Julian */
year = (jdate / 146097) * 400;
day0 = day1 = jdate %= 146097;
year += (jdate / 36524) * 100;
day2 = day1 %= 36524;
year += (day2 / 1461) * 4;
day3 = day1 %= 1461;
year += day3 / 365;
month = 1 + (day1 %= 365);
day = month % 30;
month /= 30;
if ( ( day3 >= 59 && day0 < 59 ) ||
( day3 < 59 && (day2 >= 59 || day0 < 59) ) )
++day1;
if (day1 > mthvec[1 + month]) ++month;
day = day1 - mthvec[month];
date->Dyear = year;
date->Dmonth = month;
date->Dday = day;
date->Dweekday = ds[0] % DAYS_PER_WEEK;
temp = ds[1]; /* get ds_Minute value */
date->Dhour = temp / MINS_PER_HOUR;
date->Dminute = temp % MINS_PER_HOUR;
date->Dsecond = ds[2] / TICS_PER_SEC;
return 0;
}
/* FUNCTION
DateToDS(date, dateStamp)
SYNOPSIS
void DateToDS(date, dateStamp)
DATE *date;
struct DateStamp *dateStamp;
DESCRIPTION
DateToDS converts the special DATE format to a DateStamp.
*/
DateToDS(date, ds)
DATE *date; long *ds;
{
long daysElapsed, yearsElapsed, leapYears, thisMonth, thisDay, thisYear;
int month;
/* Note the special handling for year < START_YEAR. In this case,
* the other fields are not even checked - the user just gets the
* "start of time".
*/
if ((thisYear = date->Dyear) < START_YEAR) {
ds[0] = ds[1] = ds[2] = 0;
return;
}
if (IsLeap(thisYear))
calendar[FEB].Mdays = LEAP_FEB_DAYS;
thisDay = date->Dday - 1;
thisMonth = date->Dmonth -1;
yearsElapsed = thisYear - START_YEAR;
leapYears = (yearsElapsed + LEAP_ADJUST -1) / YEARS_PER_LEAP;
daysElapsed = (yearsElapsed * DAYS_PER_YEAR) + leapYears;
for (month = 0; month < thisMonth; ++month)
daysElapsed += calendar[month].Mdays;
daysElapsed += thisDay;
calendar[FEB].Mdays = NORM_FEB_DAYS;
ds[0] = daysElapsed;
ds[1] = date->Dhour * MINS_PER_HOUR + date->Dminute;
ds[2] = date->Dsecond * TICS_PER_SEC;
}
/* FUNCTION
CompareDS - compare two DateStamp values.
SYNOPSIS
int CompareDS(date1, date2)
struct DateStamp *date1, *date2;
DESCRIPTION
CompareDS performs an ordered comparison between two DateStamp
values, returning the following result codes:
-1 => date1 < date2
0 => date1 == date2
1 => date1 > date2
NOTE:
This routine makes an assumption about the DateStamp structure,
specifically that it can be viewed as an array of 3 long integers
in days, minutes and ticks order.
*/
int
CompareDS(d1, d2)
long *d1, *d2;
{
USHORT i;
long compare;
for (i = 0; i < 3; ++i) {
if (compare = (d1[i] - d2[i])) {
if (compare < 0) return -1;
return 1;
}
}
return 0; /* dates match */
}
/* FUNCTION
DSToStr - convert a DateStamp to a formatted string.
SYNOPSIS
void DSToStr(str,fmt,d)
char *str, *fmt;
struct DateStamp *d;
DESCRIPTION
DSToStr works a little like sprintf. It converts a DateStamp
to an ascii formatted string. The formatting style is dependent
upon the contents of the format string, fmt, passed to this
function.
The content of the format string is very similar to that
for printf, with the exception that the following letters
have special significance:
y => year minus 1900
Y => full year value
m => month value as integer
M => month name
d => day of month (1..31)
D => day name ("Monday".."Sunday")
h => hour in twenty-four hour notation
H => hour in twelve hour notation
i => 12 hour indicator for H notation (AM or PM)
I => same as i
n => minutes (sorry...conflict with m = months)
N => same as n
s => seconds
S => same as s
All other characters are passed through as part of the normal
formatting process. The following are some examples with
Saturday, July 18, 1987, 13:53 as an input date:
"%y/%m/%d" => 87/7/18
"%02m/%02d/%2y" => 07/18/87
"%D, %M %d, %Y" => Saturday, July 18, 1987
"%02H:%02m i" => 01:53 PM
"Time now: %h%m" => Time now: 13:53
*/
void
DSToStr(str,fmt,d)
char *str, *fmt; long *d;
{
DATE date;
char fc,*fs,*out;
USHORT ivalue;
char new_fmt[256]; /* make it big to be "safe" */
USHORT new_fmt_lng;
char *svalue;
DSToDate(d, &date); /* convert DateStamp to DATE format */
*str = '\0'; /* insure output is empty */
out = str;
fs = fmt; /* make copy of format string pointer */
while (fc = *fs++) { /* get format characters */
if (fc == '%') { /* formatting meta-character? */
new_fmt_lng = 0;
new_fmt[new_fmt_lng++] = fc;
/* copy width information */
while (isdigit(fc = *fs++) || fc == '-')
new_fmt[new_fmt_lng++] = fc;
switch (fc) { /* what are we trying to do? */
case 'y': /* year - 1980 */
ivalue = date.Dyear % 100;
write_int:
new_fmt[new_fmt_lng++] = 'd';
new_fmt[new_fmt_lng] = '\0';
sprintf(out,new_fmt,ivalue);
out = str + strlen(str);
break;
case 'Y': /* full year value */
ivalue = date.Dyear;
goto write_int;
case 'm': /* month */
ivalue = date.Dmonth;
goto write_int;
case 'M': /* month name */
svalue = calendar[date.Dmonth - 1].Mname;
write_str:
new_fmt[new_fmt_lng++] = 's';
new_fmt[new_fmt_lng] = '\0';
sprintf(out,new_fmt,svalue);
out = str + strlen(str);
break;
case 'd': /* day */
ivalue = date.Dday;
goto write_int;
case 'D': /* day name */
svalue = dayNames[d[0] % DAYS_PER_WEEK];
goto write_str;
case 'h': /* hour */
ivalue = date.Dhour;
goto write_int;
case 'H': /* hour in 12 hour notation */
ivalue = date.Dhour;
if (ivalue >= 12) ivalue -= 12;
goto write_int;
case 'i': /* AM/PM indicator */
case 'I':
if (date.Dhour >= 12)
svalue = "PM";
else
svalue = "AM";
goto write_str;
case 'n': /* minutes */
case 'N':
ivalue = date.Dminute;
goto write_int;
case 's': /* seconds */
case 'S':
ivalue = date.Dsecond;
goto write_int;
default:
/* We are in deep caca - don't know what to do with this
* format character. Copy the raw format string to the
* output as debugging information.
*/
new_fmt[new_fmt_lng++] = fc;
new_fmt[new_fmt_lng] = '\0';
strcat(out, new_fmt);
out = out + strlen(out); /* advance string pointer */
break;
}
}
else
*out++ = fc; /* copy literal character */
}
*out = '\0'; /* terminating null */
}
/* FUNCTION
StrToDS - convert a string to a DateStamp.
SYNOPSIS
int StrToDS(string, date)
char *string;
struct DateStamp *date;
DESCRIPTION
StrToDS expects its string argument to contain a date in
MM/DD/YY HH:MM:SS format. The time portion is optional.
StrToDS will attempt to convert the string to a DateStamp
representation. If successful, it will return 0. On
failure, a 1 is returned.
*/
int
StrToDS(str, d)
char *str; long *d;
{
register char c;
int count;
int i, item;
DATE date; /* unpacked DateStamp */
char *s;
int values[3];
int value;
s = str;
for (item = 0; item < 2; ++item) { /* item = date, then time */
for (i = 0; i < 3; ++i) values[i] = 0;
count = 0;
while (c = *s++) { /* get date value */
if (c <= ' ')
break;
if (isdigit(c)) {
value = 0;
do {
value = value*10 + c - '0';
c = *s++;
} while (isdigit(c));
if (count == 3) {
bad_value:
#ifdef DEBUG
puts("Error in date-time format.\n");
printf("at %s: values(%d) = %d, %d, %d\n",
s, count, values[0], values[1], values[2]);
#endif
return 1;
}
values[count++] = value;
if (c <= ' ')
break;
}
else if (! index(DATE_SEPARATORS, c) )
goto bad_value; /* Illegal character - quit. */
} /* end while */
if (item) { /* Getting time? */
date.Dhour = values[0];
date.Dminute = values[1];
date.Dsecond = values[2];
}
else { /* Getting date? */
/* It's OK to have a null date string, but it's not OK to specify only
1 or 2 of the date components.
*/
if (count && count != 3)
goto bad_value;
date.Dmonth = values[0];
date.Dday = values[1];
date.Dyear = values[2];
if (date.Dyear == 0) {
date.Dyear = START_YEAR;
date.Dday = 1;
}
else {
if (date.Dyear < (START_YEAR - 1900) )
date.Dyear += 100;
date.Dyear += 1900;
}
}
} /* end for */
DateToDS(&date, d);
return 0;
} /* StrToDS */
#ifdef DEBUG
#include "stdio.h"
main(ac, av)
int ac;
char **av;
{
long datestamp[3]; /* A little dangerous with Aztec */
long datestamp2[3];
DATE date, oldDate;
long day, lastDay;
int errors = 0;
/*
* display results from DateStamp() (hours:minutes:seconds)
*/
DateStamp(datestamp);
/*
* display results from DSToDate() (e.g. "03-May-88")
*/
DSToDate(datestamp, &date);
printf("Current date: %02d-%s-%02d\n",
date.Dday, calendar[ date.Dmonth - 1].Mname,
(date.Dyear % YEARS_PER_CENTURY));
printf("Current time: %02d:%02d:%02d\n",
date.Dhour, date.Dminute, date.Dsecond);
printf("\nDoing sanity check through year 2000...\n\t");
lastDay = (2000L - START_YEAR) * 365L;
lastDay += (2000L - START_YEAR) / YEARS_PER_LEAP;
for (day = 0; day <= lastDay; ++day) {
if (day % 1000 == 0) {
printf(" %ld", day);
fflush(stdout);
}
datestamp[0] = day;
datestamp[1] = MINS_PER_HOUR - 1;
datestamp[2] = TICS_PER_SEC * (SECS_PER_MIN - 1);
DSToDate(datestamp, &date);
if (day && date == oldDate) {
printf("Got same date for days %d, %d: %02d-%s-%02d\n",
day - 1, day,
date.Dday,
calendar[ date.Dmonth - 1 ].Mname,
(date.Dyear % YEARS_PER_CENTURY));
if (++errors == 10)
exit(1);
}
DateToDS(&date, datestamp2);
if (day != datestamp2[0]) {
printf("\nConversion mismatch at day %ld!\n", day);
printf("\tBad value = %ld", datestamp2[0]);
printf("\tDate: %02d-%s-%02d\n",
date.Dday,
calendar[ date.Dmonth -1 ].Mname,
(date.Dyear % YEARS_PER_CENTURY));
if (++errors == 10)
exit(1);
}
oldDate = date;
}
printf("\nSanity check passed.\n");
} /* main() */
#endif